from flask import Flask, request, session, redirect, url_for, render_template
from flask_mysqldb import MySQL
from argon2 import PasswordHasher
import os
from functools import wraps
from datetime import datetime, timedelta
from collections import defaultdict

app = Flask(__name__)

# Configuration
app.secret_key = os.getenv('FLASK_SECRET_KEY', 'placeholder')
app.config.update(
    SESSION_COOKIE_SECURE=True,
    SESSION_COOKIE_HTTPONLY=True,
    SESSION_COOKIE_SAMESITE='Lax',
    MYSQL_HOST='localhost',
    MYSQL_USER='lfaiwvfjtv_Espie',
    MYSQL_PASSWORD='Keftlqds#111!',
    MYSQL_DB='lfaiwvfjtv_auth_db',
    MYSQL_POOL_SIZE=10
)

mysql = MySQL(app)
ph = PasswordHasher()

# Rate limiting
attempt_tracker = defaultdict(list)
MAX_ATTEMPTS = 5
WINDOW_MINUTES = 5

def check_rate_limit(ip_address):
    now = datetime.now()
    window_start = now - timedelta(minutes=WINDOW_MINUTES)
    
    # Clean old attempts
    attempt_tracker[ip_address] = [
        attempt for attempt in attempt_tracker[ip_address]
        if attempt > window_start
    ]
    
    # Check if limit exceeded
    if len(attempt_tracker[ip_address]) >= MAX_ATTEMPTS:
        return False
    
    attempt_tracker[ip_address].append(now)
    return True

def login_required(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if 'user_id' not in session:
            return redirect(url_for('login'))
        return f(*args, **kwargs)
    return decorated_function

@app.route('/register', methods=['GET', 'POST'])
def register():
    if request.method == 'POST':
        if not check_rate_limit(request.remote_addr):
            return 'Too many attempts. Please try again later.', 429
            
        username = request.form['username']
        password = request.form['password']
        
        cur = mysql.connection.cursor()
        
        # Check for existing username
        cur.execute("SELECT id FROM users WHERE username = %s", (username,))
        if cur.fetchone():
            cur.close()
            return 'Username already exists', 400
            
        # Hash password and store user
        password_hash = ph.hash(password)
        cur.execute("INSERT INTO users (username, password_hash) VALUES (%s, %s)",
                   (username, password_hash))
        mysql.connection.commit()
        cur.close()
        
        return redirect(url_for('login'))
        
    return render_template('register.html')

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        if not check_rate_limit(request.remote_addr):
            return 'Too many attempts. Please try again later.', 429
            
        username = request.form['username']
        password = request.form['password']
        
        cur = mysql.connection.cursor()
        cur.execute("SELECT id, password_hash FROM users WHERE username = %s",
                   (username,))
        user = cur.fetchone()
        cur.close()
        
        if user and ph.verify(user[1], password):
            session['user_id'] = user[0]
            return redirect(url_for('index'))
            
        return 'Invalid username or password', 401
        
    return render_template('login.html')

@app.route('/logout')
def logout():
    session.clear()
    return redirect(url_for('index'))

# Database initialization
def init_db():
    cur = mysql.connection.cursor()
    cur.execute('''
        CREATE TABLE IF NOT EXISTS users (
            id INT AUTO_INCREMENT PRIMARY KEY,
            username VARCHAR(255) UNIQUE NOT NULL,
            password_hash VARCHAR(255) NOT NULL,
            created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
        )
    ''')
    mysql.connection.commit()
    cur.close()

with app.app_context():
    init_db()
